package org.sepheriel.airy2d.shader;

import org.lwjgl.opengl.GL11;
import java.io.BufferedReader;
import java.io.FileReader;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.ARBShaderObjects;
import org.lwjgl.opengl.ARBVertexShader;
import org.lwjgl.opengl.ARBFragmentShader;
import org.lwjgl.opengl.EXTFramebufferObject;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.Util;
import org.sepheriel.airy2d.math.Vec2;


public abstract class PostFX {
	
	private boolean useShader = true;
	
	protected int shader = 0;
	private int vertShader = 0;
	private int fragShader = 0;
	
	private Vec2 resolution;
	
	public PostFX(Vec2 r, String pathv, String pathf) {
		
		resolution = r;
		
		shader = ARBShaderObjects.glCreateProgramObjectARB();
		
		if(shader != 0) {
			vertShader = createVertShader(pathv);
			fragShader = createFragShader(pathf);
		} else {
			useShader = false;
		}
		
		if(vertShader != 0 && fragShader != 0) {
			ARBShaderObjects.glAttachObjectARB(shader, vertShader);
			ARBShaderObjects.glAttachObjectARB(shader, fragShader);
			ARBShaderObjects.glLinkProgramARB(shader);
			ARBShaderObjects.glValidateProgramARB(shader);
			
		} else {
			useShader = false;
		}
	}
		
		public void draw(int frame, int delta) {
			
			if(useShader) {
				ARBShaderObjects.glUseProgramObjectARB(shader);
				initVars(delta);
			}
			
			EXTFramebufferObject.glBindFramebufferEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, frame );
		
			GL11.glEnable(GL11.GL_TEXTURE_2D);
			GL11.glBindTexture(GL11.GL_TEXTURE_2D, frame);
			GL11.glBegin(GL11.GL_QUADS);
			
				GL11.glTexCoord2f(0, 1);
				GL11.glVertex2f(0, 0);

				GL11.glTexCoord2f(1, 1);
				GL11.glVertex2f(this.resolution.getX(), 0);

				GL11.glTexCoord2f(1, 0);
				GL11.glVertex2f(this.resolution.getX(),this.resolution.getY());

				GL11.glTexCoord2f(0, 0);
				GL11.glVertex2f(0,this.resolution.getY());
				
			GL11.glEnd();
			GL11.glDisable(GL11.GL_TEXTURE_2D);

			EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
			
			GL11.glClearColor(0f, 0f, 0f, 0f);
			GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
			GL11.glLoadIdentity();		
			GL11.glViewport( 0, 0, (int)this.resolution.getX(), (int)this.resolution.getY());	

			GL11.glEnable(GL11.GL_TEXTURE_2D);
			GL11.glBindTexture(GL11.GL_TEXTURE_2D, frame);
			GL11.glBegin(GL11.GL_QUADS);
			
				GL11.glTexCoord2f(0, 1);
				GL11.glVertex2f(0, 0);

				GL11.glTexCoord2f(1, 1);
				GL11.glVertex2f(this.resolution.getX(), 0);

				GL11.glTexCoord2f(1, 0);
				GL11.glVertex2f(this.resolution.getX(),this.resolution.getY());

				GL11.glTexCoord2f(0, 0);
				GL11.glVertex2f(0,this.resolution.getY());
				
			GL11.glEnd();
			GL11.glDisable(GL11.GL_TEXTURE_2D);
			
				
				ARBShaderObjects.glUseProgramObjectARB(0);
			}

		
		
		private int createVertShader(String filename) {

			vertShader=ARBShaderObjects.glCreateShaderObjectARB(ARBVertexShader.GL_VERTEX_SHADER_ARB);

		if(vertShader==0){return 0;}
			String vertexCode="";
			String line;
		try{
			BufferedReader reader=new BufferedReader(new FileReader(filename));
				while((line=reader.readLine())!=null){
					vertexCode+=line + "\n";
				}
			}catch(Exception e){
				System.out.println("Fail reading vertex shading code");
				return 0;
			}

			ARBShaderObjects.glShaderSourceARB(vertShader, vertexCode);
			ARBShaderObjects.glCompileShaderARB(vertShader);
			
			return vertShader;
		}
		

		private int createFragShader(String filename){
			
			fragShader=ARBShaderObjects.glCreateShaderObjectARB(ARBFragmentShader.GL_FRAGMENT_SHADER_ARB);
			
		if(fragShader==0){return 0;}
			String fragCode="";
			String line;
		try{
			BufferedReader reader=new BufferedReader(new FileReader(filename));
				while((line=reader.readLine())!=null){
					fragCode+=line + "\n";
				}
		}catch(Exception e){
			System.out.println("Fail reading fragment shading code");
			return 0;
		}
			ARBShaderObjects.glShaderSourceARB(fragShader, fragCode);
			ARBShaderObjects.glCompileShaderARB(fragShader);

			return fragShader;
		}

		public abstract void initVars(int delta);
		
	}

